const targetMap = new WeakMap();

function track(target, key) {
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    depsMap = new Map();
    targetMap.set(target, depsMap);
  }
  let dep = depsMap.get(key);
  if (!dep) {
    dep = new Set();
    depsMap.set(key, dep);
  }
  if (Dep.target) {
    dep.add(Dep.target);
  }
}

function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  if (dep) {
    dep.forEach(effect => effect());
  }
}

class Observer {
  constructor(data) {
    if (typeof Proxy !== 'undefined') {
      return new Proxy(data, {
        get(target, key) {
          track(target, key);
          return target[key];
        },
        set(target, key, value) {
          if (value !== target[key]) {
            target[key] = value;
            trigger(target, key);
          }
          return true;
        }
      });
    } else {
      // 降级为 Object.defineProperty
      Object.keys(data).forEach(key => {
        let value = data[key];
        Object.defineProperty(data, key, {
          get() {
            track(data, key);
            return value;
          },
          set(newValue) {
            if (newValue !== value) {
              value = newValue;
              trigger(data, key);
            }
          }
        });
      });
      return data;
    }
  }
}

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    this.subs.push(sub);
  }

  notify() {
    this.subs.forEach(sub => sub.update());
  }
}

Dep.target = null;

function observe(data) {
  return new Observer(data);
}

export { observe, Dep };